/* 
Copyright 2011 Michael Mallon

This file is part of SQAT.

SQAT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

SQAT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with SQAT.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>

#include "LadderOperator.h"

using namespace std;

LadderOperator::LadderOperator(void)
{
	site = string("");
	basis = string("");
	creation = false;
	fermion = false;
}


LadderOperator::~LadderOperator(void)
{
}

LadderOperator::LadderOperator(string site, string basis, bool creation, bool fermion)
{
	(*this).site = site;
	(*this).basis = basis;
	(*this).creation = creation;
	(*this).fermion = fermion;
}


complex<double> LadderOperator::commuteWith(LadderOperator A)
{
	//fermions. These do not commute.
	if (A.isFermion() && (*this).isFermion()) {
		cerr << "Commutation [" << (*this).toString() << ", " << A.toString() << "] is invalid" << endl;
		throw;
	}

	// Not the same types of operators. These commute.
	if ((A.isBoson() && (*this).isFermion())||(A.isFermion() && (*this).isBoson())) {
			return complex<double>(0,0);
	}

	//have bosons
	if (A.getSite().compare((*this).getSite()) == 0) {
		// at the same site
		if ((*this).isAnnhiliation()) {
			if (A.isAnnhiliation()) {
				// [a, a] = 0
				return complex<double>(0,0);
			} else {
				// [a, a+] = 1
				return complex<double>(1,0);
			}
		} else {
			if (A.isAnnhiliation()) {
				// [a+, a] = -1
				return complex<double>(-1,0);
			} else {
				// [a+, a+] = 0
				return complex<double>(0,0);
			}
		}
		
	} else {
		// different sites
		return complex<double>(0,0);
	}
}

complex<double> LadderOperator::anticommuteWith(LadderOperator C)
{
	//Bosons do not anti-commute
	if (C.isBoson() || (*this).isBoson()) {
			cerr << "Anti-Commutation {" << (*this).toString() << ", " << C.toString() << "} is invalid" << endl;
			throw;
	}

	// have fermions
	if (C.getSite().compare((*this).getSite()) == 0) {
		// at the same site
		if (((*this).isAnnhiliation() && C.isCreation())
				||((*this).isCreation() && C.isAnnhiliation())) {
			// {c, c+} = {c+, c} = 1
			return complex<double>(1,0);
		} else {
			// {c, c} and {c+, c+} are invald as c's at the same site are fundamentally zero
			cerr << "Anti-Commutation {" << (*this).toString() << ", " << C.toString() << "} is invalid" << endl;
			throw;
		}
	} else {
		// different sites
		return complex<double>(0,0);
	}

}

LadderOperator LadderOperator::getConjugate(void)
{
	LadderOperator o = LadderOperator();
	o.setBasis((*this).getBasis());
	o.setCreation(!(*this).getCreation());
	o.setFermion((*this).getFermion());
	o.setSite((*this).getSite());

	return o;
}

void LadderOperator::conjugate(void)
{
	creation = !creation;
	return;
}

string LadderOperator::getSite(void)
{
	return string(site);
}

void LadderOperator::setSite(string s)
{
	site = string(s);
	return;
}

string LadderOperator::getBasis(void)
{
	
	return string(basis);
}

void LadderOperator::setBasis(string s)
{
	basis = string(s);
	return;
}

bool LadderOperator::getCreation(void)
{
	return creation;
}

void LadderOperator::setCreation(bool x)
{
	creation = x;
	return;
}

bool LadderOperator::getFermion(void)
{
	return fermion;
}

void LadderOperator::setFermion(bool x)
{
	fermion = x;
	return;
}

string LadderOperator::toString()
{
	string s = string();
	if ((*this).getFermion() == true) {
		s = string("c");
	} else {
		s = string("a");
	}
	if ((*this).getCreation() == true) {
		s = s+"^{\\dagger}";
	}
	s = s + string("_{") + (*this).getSite() + string("}");
	return s;
}

bool LadderOperator::isBoson(void)
{
	return !(fermion);
}
bool LadderOperator::isFermion(void)
{
	return fermion;
}
bool LadderOperator::isCreation(void)
{
	return creation;
}
bool LadderOperator::isAnnhiliation(void)
{
	return !(creation);
}
